BRIC Project

# clear workspace
##rm(list=ls())

getting the current WD

getwd()

changing the WD

##setwd("/Users/Manu/Desktop/TUM_Master_Mgt_Technology/TUM_SS_21/Empirical Asset Pricing seminar/Seminar Thesis/BRIC_data")

Loading Libraries

# loading libraries
library(data.table) # extension of the data.frame package. It is widely used for fast aggregation of large datasets, low latency add/update/remove of columns, quicker ordered joins, and a fast file reader.
library(dplyr) # data manipulation package
library(lubridate)
library(zoo) # methods for totally ordered indexed observations. It aims at performing calculations containing irregular time series of numeric vectors, matrices & factors

library(stats)
library(utils)
library(tidyverse)

Loading in the R.data

Data column descriptions (Worldscope): https://www.professors.wi.tum.de/fileadmin/w00bca/fm/Worldscope_Data_Definition_Guide_Issue_15.pdf

https://docs.google.com/spreadsheets/d/1YtuJiv60Q6nKIaFJLQY60sGQErbsl_8nvPdUHmvO8vM/edit?usp=sharing

memory.limit(9999999999)
[1] 1e+10

Clearing data from dates before July 1994 and NA s in RET.USD

# save raw data and adjust others to the required date range
BRIC.monthly.raw <- BRIC.monthly
BRIC.monthly <- subset(BRIC.monthly, Date >= "1994-06-30" & Date <= "2019-01-01")
BRIC.monthly <- na.omit(BRIC.monthly,cols = "RET.USD")

BRIC.yearly.raw <- BRIC.yearly
BRIC.yearly <- subset(BRIC.yearly, YEAR >= "1994" & YEAR <= "2019")

ISIN: International Security Identification Number (stock identifier) ESTAT: active vs inactive company (publicly listed or not) Id: join column with BRIC.yearly dataframe INDM: industry sector code

GEOGN: geographic group name GEOLN: geographic location

List of Database codes: https://www.bwl.uni-mannheim.de/media/Lehrstuehle/bwl/Maug/Database_info/Datastream_dataypes.pdf

ID: ?? Country: 4 BRIC COUNTRY CODES ICBSUC: industrial classification benchmark https://link.springer.com/content/pdf/bbm%3A978-3-8350-9531-1%2F1.pdf

WC07021: SIC(standard industrial classification) primary code from Worldscope W05651: Common Shares Traded - Annual (Security)

TO DO’s:

Project Dates: Thesis submission: June 21 Final presentation: June 07

Strategy: GDP weighted countries; stock level: max sharpe ratio, min volatility, equal sector weights or quotas, momentum?

EDA

# finding the number of NA values by column in the dataframe
BRIC.monthly %>% mutate_all(is.na) %>% summarize_all(sum)

To DO: compute correlations by sector (10 sectors)

# regular correlation matrix of all (four) numeric attributes
cor(select(BRIC.static, where(is.numeric)))

Some conventions:

Characteristic should be calculated as in Hanauer & Lauterbach (2019) or in Hanauer (2020)

Big stocks should be defined as the biggest stocks which together account for 90% of a country’s aggregated market capitalization Benchmark should be defined as the cap-weighted universe of big stocks Returns should be in USD Breakpoints (for Fama-French factors) should be calculated on big stocks (as in the excursus) but both small and big stocks go into the factor calculation.

Benchmark Calculation

length(BRIC.static$Id)

length(BRIC.yearly$Id)
# joining the monthly and the static dataframe by the Id column (retainig all rows of BRIC.yearly)
df_combined <- left_join(x=BRIC.monthly,y=BRIC.static,by="Id")


head(df_combined)
summary(df_combined$MV.USD)
## finding the number of NA values by column in the dataframe
BRIC.yearly %>% mutate_all(is.na) %>% summarize_all(sum)
# markt cap (USD): WC07210

## finding the number of NA values by column in the dataframe
df_combined %>% mutate_all(is.na) %>% summarize_all(sum)

Idea: calculate 90% of the sum of all stock market caps per country as a time series (store the result in a column )

# Big stocks should be defined as the biggest stocks which together account for 90% of # a country's aggregated market capitalization


# grouping the mcap values of individual stocks by country
mcap_country <- df_combined %>%
  filter(df_combined$MV.USD != "NA") %>% 
  group_by(country.x, ym) 

# computing the sum of the individual stock's market caps by country
country_mcap <- mcap_country %>%
group_by(country.x, ym) %>%
    summarize(mc_sum = sum(MV.USD))

country_mcap
summary(country_mcap$mc_sum[country_mcap$country.x == "BRA"])
summary(country_mcap$mc_sum[country_mcap$country.x == "RUS"])
summary(country_mcap$mc_sum[country_mcap$country.x == "IND"])
summary(country_mcap$mc_sum[country_mcap$country.x == "CHN"])

FF5FM Calulation new

## 1 month t-bill rate
# load data sheet from French's website
library(readr)
FFData <- read_csv("FF_Research_Data_5_Factors_2x3.CSV", 
     skip = 2)
Missing column names filled in: 'X1' [1]
-- Column specification -------------------------------------------------------------------------------------------------------------------------
cols(
  X1 = col_character(),
  `Mkt-RF` = col_character(),
  SMB = col_character(),
  HML = col_character(),
  RMW = col_character(),
  CMA = col_character(),
  RF = col_character()
)

1 parsing failure.
row col  expected    actual                                 file
694  -- 7 columns 1 columns 'FF_Research_Data_5_Factors_2x3.CSV'
# adding a ym column to risk free rate data
one_m_tbill <- as.data.frame(FFData[c("X1","RF")][1:693,])

one_m_tbill$ym<-as.yearmon(one_m_tbill$X1, "%Y %m")

# merge risk-free rate (1 month treasury bill rate) with monthly data
BRIC.monthly_full <- left_join(x = BRIC.monthly, y = one_m_tbill, by = "ym")

# make rf column numeric
BRIC.monthly_full$RF <- as.numeric(BRIC.monthly_full$RF)

calculate RMRF

BRIC.monthly_full$RMRF <- BRIC.monthly_full$RET.USD - BRIC.monthly_full$RF

Calculate SMB and HML

comment: na values appear for size calculation, which differs from what in the excursus note: we omitted the na’s for further calculation –> has to be clarified in the Q&A session with Hanauer

we didn’t calculate the lagged MV yet lines 271,315

## Determine portfolio breakpoints for Size
# Fama-French take the MV from end-of-June and rebalance yearly
BRIC.monthly_full[,month := month(Date)]
BRIC.monthly_full[,year := year(Date)]
BRIC.monthly_full[,hcjun := ifelse(month>=7,year,year-1)]

# determine size portfolio allocation from July on using data that's public from end-of-June on

# we didn't calculate the lagged MV yet 

setorder(BRIC.monthly_full,Date,-MV.USD)
hlpvariable <-  BRIC.monthly_full[month==7 & !is.na(MV.USD),
                .(Size = ifelse((cumsum(MV.USD)/sum(MV.USD))>=0.9,"Small","Big"),Id),
                               by=year]

# Merge the size portfolio allocation back from July Y to June Y+1
panel_country <- merge(BRIC.monthly_full,hlpvariable,
                       by.x=c("hcjun","Id"),
                       by.y=c("year","Id"),
                       all.x=T)

panel_country_noNA <- na.omit(panel_country,cols = "Size") 

# merge yearly BM data with our table
BRIC.yearly_helper <- subset( BRIC.yearly, select = c("Id","country","ICBSUC","YEAR","WC03501","WC07210","WC01001","WC01051","WC01101","WC01251","WC02999") )
BRIC.yearly_helper$BM <- BRIC.yearly_helper$WC03501 / BRIC.yearly_helper$WC07210

# delete NA s from BM column
BRIC.yearly_helper <- na.omit(BRIC.yearly_helper,cols = "BM")

summary(BRIC.yearly_helper$BM)
      Min.    1st Qu.     Median       Mean    3rd Qu.       Max. 
-119910.70       1.96       6.14        Inf      42.55        Inf 
# eliminating unused columns
panel_country_noNA <- subset(panel_country_noNA, select = c("hcjun","Id","country","MV.USD","RET.USD","ym","RF","month","year","Size","Date"))

panel_country_BM <- inner_join(x = panel_country_noNA,y = BRIC.yearly_helper, by = "Id")


# Determine the B/M breakpoints based on big stocks only
hlpvariable2 <- panel_country_BM[month==7 & !is.na(BM) & Size=="Big", .(bm_bb30 = quantile(BM , probs = c(0.3), na.rm=T),
                                                                        bm_bb70 = quantile(BM , probs = c(0.7), na.rm=T)),by=year]
              
# Merge the B/M portfolio allocation back from July Y to June Y+1
panel_country_new <- merge(panel_country_BM,hlpvariable2,
                       by.x=c("hcjun"),
                       by.y=c("year"),
                       all.x=T)

panel_country_new[ , pf.bm := ifelse(BM>bm_bb70,"High",ifelse((BM<=bm_bb70 & BM>bm_bb30),"Neutral",ifelse(BM<=bm_bb30,"Low",NA)))]

panel_country_new[, SIZE_VALUE := paste0(Size,".",pf.bm)]

# we used MV.USD instead of the lagged MV

portfolio_returns <- panel_country_new[!is.na(Size) & !is.na(pf.bm)] %>% # this operator nests functions
  group_by(Date,SIZE_VALUE) %>% # do "everything" for the groups specified here
  summarize(ret.port = weighted.mean(RET.USD,
                                     MV.USD)) %>% # vw returns using lagged mcap
  spread(SIZE_VALUE,ret.port) %>% # create one column for each group
  mutate(
    Small = (Small.High + Small.Neutral + Small.Low)/3, # just exemplary
    Big = (Big.High + Big.Neutral + Big.Low)/3,
    SMB = Small-Big,
    High = (Small.High + Big.High)/2,
    Low = (Small.Low + Big.Low)/2,
    HML = High-Low
  )
`summarise()` has grouped output by 'Date'. You can override using the `.groups` argument.
portfolio_returns <- as.data.table(portfolio_returns)

head(portfolio_returns)
NA

RMW

profitability: OP/BE: Operating profits-to-book equity. We measure operating profits-to-book equity as in Fama and French (2015) as sales or revenues (WC01001) minus cost of goods sold (WC01051), minus selling, general, and administrative expenses (WC01101), minus interest expense (WC01251); all divided by book equity. (Hanauer, 2019, p. 284)

# use BRIC.yearly_helper

CMA

investment: As in Cooper et al. (2008), we measure asset growth in June of year y as the percentage change in total assets (WC02999) from fiscal year ending in calendar year y−2 to fiscal year ending in calendar year y−1.

# use BRIC.yearly_helper

Strategy

number_of_stocks <- aggregate(.~ ym, data = sd_help,FUN = NROW)
mean_return <- aggregate(.~ ym, data = sd_help,FUN = mean)
sd_help %>% count(ym)
# sorting the stocks by market cap and extracting the ISINs of the biggest ones that make up 90% of a country's market cap

# RUSSIA
# 90% of the market cap in Russia: 
0.9*country_mcap$mc_sum[4]

# subsetting all Russian stocks
russian_stocks <- as.data.frame(mcap_country) %>%
   filter(country.x == "RUS") 

# sorting the dataframe of russian stocks by decreasing market cap
russian_stocks <- russian_stocks[order(russian_stocks$WC07210,decreasing = TRUE),]
 
# filtering out the big stocks which sum up to 90% of the market cap of Russian stocks
big_stocks_RUS <- russian_stocks[cumsum(russian_stocks$WC07210) <= 0.9*country_mcap$mc_sum[4],]

big_stocks_RUS

idea:

big_stocks <- mcap_country %>% select(ISIN) %>% sort(mcap_country\(WC07210, decreasing=T) %>% filter(mcap_country\)WC07210 <= 0.9*country_mcap$mc_sum)

big_stocks

# sorting the stocks by market cap and extracting the ISINs of the biggest ones that make up 90% of a country's market cap

# RUSSIA
# 90% of the market cap in Russia: 
0.9*country_mcap$mc_sum[4]

# subsetting all Russian stocks
russian_stocks <- as.data.frame(mcap_country) %>%
   filter(country.x == "RUS") 

# sorting the dataframe of russian stocks by decreasing market cap
russian_stocks <- russian_stocks[order(russian_stocks$WC07210,decreasing = TRUE),]
 
# filtering out the big stocks which sum up to 90% of the market cap of Russian stocks
big_stocks_RUS <- russian_stocks[cumsum(russian_stocks$WC07210) <= 0.9*country_mcap$mc_sum[4],]

big_stocks_RUS



  

Calculating the size portfolios

LS0tDQp0aXRsZTogIkJSSUNfcHJvamVjdCINCmF1dGhvcjogDQogIG5hbWU6IE1hbnVlbCBTY2hyZWliZXINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0aGVtZTogdW5pdGVkDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgbGF0ZXhfZW5naW5lOiBwZGZsYXRleA0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCiAgaGVhZGVyLWluY2x1ZGVzOg0KICAgLSBcdXNlcGFja2FnZXthbXNtYXRofQ0KICAgLSBcdXNlcGFja2FnZXthbXNmb250c30NCi0tLQ0KDQoqKkJSSUMgUHJvamVjdCoqDQoNCmBgYHtyfQ0KIyBjbGVhciB3b3Jrc3BhY2UNCiMjcm0obGlzdD1scygpKQ0KYGBgDQoNCg0KZ2V0dGluZyB0aGUgY3VycmVudCBXRA0KDQpgYGB7cn0NCmdldHdkKCkNCmBgYA0KDQpjaGFuZ2luZyB0aGUgV0QNCg0KYGBge3J9DQojI3NldHdkKCIvVXNlcnMvTWFudS9EZXNrdG9wL1RVTV9NYXN0ZXJfTWd0X1RlY2hub2xvZ3kvVFVNX1NTXzIxL0VtcGlyaWNhbCBBc3NldCBQcmljaW5nIHNlbWluYXIvU2VtaW5hciBUaGVzaXMvQlJJQ19kYXRhIikNCmBgYA0KDQojIExvYWRpbmcgTGlicmFyaWVzDQoNCmBgYHtyfQ0KIyBsb2FkaW5nIGxpYnJhcmllcw0KbGlicmFyeShkYXRhLnRhYmxlKSAjIGV4dGVuc2lvbiBvZiB0aGUgZGF0YS5mcmFtZSBwYWNrYWdlLiBJdCBpcyB3aWRlbHkgdXNlZCBmb3IgZmFzdCBhZ2dyZWdhdGlvbiBvZiBsYXJnZSBkYXRhc2V0cywgbG93IGxhdGVuY3kgYWRkL3VwZGF0ZS9yZW1vdmUgb2YgY29sdW1ucywgcXVpY2tlciBvcmRlcmVkIGpvaW5zLCBhbmQgYSBmYXN0IGZpbGUgcmVhZGVyLg0KbGlicmFyeShkcGx5cikgIyBkYXRhIG1hbmlwdWxhdGlvbiBwYWNrYWdlDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoem9vKSAjIG1ldGhvZHMgZm9yIHRvdGFsbHkgb3JkZXJlZCBpbmRleGVkIG9ic2VydmF0aW9ucy4gSXQgYWltcyBhdCBwZXJmb3JtaW5nIGNhbGN1bGF0aW9ucyBjb250YWluaW5nIGlycmVndWxhciB0aW1lIHNlcmllcyBvZiBudW1lcmljIHZlY3RvcnMsIG1hdHJpY2VzICYgZmFjdG9ycw0KDQpsaWJyYXJ5KHN0YXRzKQ0KbGlicmFyeSh1dGlscykNCmxpYnJhcnkodGlkeXZlcnNlKQ0KDQpgYGANCg0KDQojIExvYWRpbmcgaW4gdGhlIFIuZGF0YQ0KDQpEYXRhIGNvbHVtbiBkZXNjcmlwdGlvbnMgKFdvcmxkc2NvcGUpOg0KaHR0cHM6Ly93d3cucHJvZmVzc29ycy53aS50dW0uZGUvZmlsZWFkbWluL3cwMGJjYS9mbS9Xb3JsZHNjb3BlX0RhdGFfRGVmaW5pdGlvbl9HdWlkZV9Jc3N1ZV8xNS5wZGYNCg0KaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMVl0dUppdjYwUTZuS0lhRkpMUVk2MHNHUUVyYnNsXzhudlBkVUhtdk84dk0vZWRpdD91c3A9c2hhcmluZw0KDQoNCmBgYHtyfQ0KbWVtb3J5LmxpbWl0KDk5OTk5OTk5OTkpDQojIGxvYWRpbmcgUi5kYXRhIEJSSUMgbW9udGhseQ0KbG9hZCgiQzovVXNlcnMvam9oYW4vRG9jdW1lbnRzL0JSSUNfQXNzZXRfUHJpY2luZ19Qcm9qZWN0L0JSSUNfbW9udGhseS5SRGF0YSIpDQoNCiMgbG9hZGluZyBSLmRhdGEgQlJJQyBtb250aGx5DQpsb2FkKCJDOi9Vc2Vycy9qb2hhbi9Eb2N1bWVudHMvQlJJQ19Bc3NldF9QcmljaW5nX1Byb2plY3QvQlJJQ19zdGF0aWMuUkRhdGEiKQ0KDQojIGxvYWRpbmcgUi5kYXRhIEJSSUMgbW9udGhseQ0KbG9hZCgiQzovVXNlcnMvam9oYW4vRG9jdW1lbnRzL0JSSUNfQXNzZXRfUHJpY2luZ19Qcm9qZWN0L0JSSUNfeWVhcmx5LlJEYXRhIikNCg0KYGBgDQojIENsZWFyaW5nIGRhdGEgZnJvbSBkYXRlcyBiZWZvcmUgSnVseSAxOTk0IGFuZCBOQSBzIGluIFJFVC5VU0QNCg0KYGBge3J9DQojIHNhdmUgcmF3IGRhdGEgYW5kIGFkanVzdCBvdGhlcnMgdG8gdGhlIHJlcXVpcmVkIGRhdGUgcmFuZ2UNCkJSSUMubW9udGhseS5yYXcgPC0gQlJJQy5tb250aGx5DQpCUklDLm1vbnRobHkgPC0gc3Vic2V0KEJSSUMubW9udGhseSwgRGF0ZSA+PSAiMTk5NC0wNi0zMCIgJiBEYXRlIDw9ICIyMDE5LTAxLTAxIikNCkJSSUMubW9udGhseSA8LSBuYS5vbWl0KEJSSUMubW9udGhseSxjb2xzID0gIlJFVC5VU0QiKQ0KDQpCUklDLnllYXJseS5yYXcgPC0gQlJJQy55ZWFybHkNCkJSSUMueWVhcmx5IDwtIHN1YnNldChCUklDLnllYXJseSwgWUVBUiA+PSAiMTk5NCIgJiBZRUFSIDw9ICIyMDE5IikNCg0KDQpgYGANCg0KSVNJTjogSW50ZXJuYXRpb25hbCBTZWN1cml0eSBJZGVudGlmaWNhdGlvbiBOdW1iZXIgKHN0b2NrIGlkZW50aWZpZXIpDQpFU1RBVDogYWN0aXZlIHZzIGluYWN0aXZlIGNvbXBhbnkgKHB1YmxpY2x5IGxpc3RlZCBvciBub3QpDQpJZDogam9pbiBjb2x1bW4gd2l0aCBCUklDLnllYXJseSBkYXRhZnJhbWUNCklORE06IGluZHVzdHJ5IHNlY3RvciBjb2RlDQoNCkdFT0dOOiBnZW9ncmFwaGljIGdyb3VwIG5hbWUNCkdFT0xOOiBnZW9ncmFwaGljIGxvY2F0aW9uDQoNCkxpc3Qgb2YgRGF0YWJhc2UgY29kZXM6DQpodHRwczovL3d3dy5id2wudW5pLW1hbm5oZWltLmRlL21lZGlhL0xlaHJzdHVlaGxlL2J3bC9NYXVnL0RhdGFiYXNlX2luZm8vRGF0YXN0cmVhbV9kYXRheXBlcy5wZGYNCg0KSUQ6ID8/DQpDb3VudHJ5OiA0IEJSSUMgQ09VTlRSWSBDT0RFUw0KSUNCU1VDOiBpbmR1c3RyaWFsIGNsYXNzaWZpY2F0aW9uIGJlbmNobWFyaw0KaHR0cHM6Ly9saW5rLnNwcmluZ2VyLmNvbS9jb250ZW50L3BkZi9iYm0lM0E5NzgtMy04MzUwLTk1MzEtMSUyRjEucGRmDQoNCldDMDcwMjE6IFNJQyhzdGFuZGFyZCBpbmR1c3RyaWFsIGNsYXNzaWZpY2F0aW9uKSBwcmltYXJ5IGNvZGUgZnJvbSBXb3JsZHNjb3BlDQpXMDU2NTE6IENvbW1vbiBTaGFyZXMgVHJhZGVkIC0gQW5udWFsIChTZWN1cml0eSkNCg0KDQoqVE8gRE8ncyo6DQoNCi0gQ2FsY3VsYXRlIEJlbmNobWFyayAobWFya2V0LWNhcCB3ZWlnaHRlZCBiaWcgc3RvY2tzIG9mIHRoZSBCUklDIHJlZ2lvbikNCi0gQ2FsY3VsYXRlIGJyZWFrIHBvaW50cyBvbiBiaWcgc3RvY2tzDQotIGRlY2lkZSBvbiBzdHJhdGVneSBhbmQgaW1wbGVtZW50IGl0DQotIGNhbGN1bGF0ZSBwb3J0Zm9saW8gY2hhcmFjdGVyaXN0aWNzDQotIHZpc3VhbGl6ZSBhbmQgc2hvd2Nhc2Ugc3RyYXRlZ3kgcGVyZm9ybWFuY2UNCi0gcmVncmVzcyBzdHJhdGVneSBQRiBvbiBGRjVGTSBhbmQgbW9tZW50dW0gZm9yIHN0eWxlIGV4cG9zdXJlIGFuYWx5c2lzDQotIExpdGVyYXR1cmUgDQoNCg0KKlByb2plY3QgRGF0ZXMqOg0KVGhlc2lzIHN1Ym1pc3Npb246IEp1bmUgMjENCkZpbmFsIHByZXNlbnRhdGlvbjogSnVuZSAwNw0KDQoqU3RyYXRlZ3kqOg0KR0RQIHdlaWdodGVkIGNvdW50cmllczsgc3RvY2sgbGV2ZWw6IG1heCBzaGFycGUgcmF0aW8sIG1pbiB2b2xhdGlsaXR5LCBlcXVhbCBzZWN0b3Igd2VpZ2h0cyBvciBxdW90YXMsIG1vbWVudHVtPw0KDQoNCkVEQQ0KDQpgYGB7cn0NCiMgZmluZGluZyB0aGUgbnVtYmVyIG9mIE5BIHZhbHVlcyBieSBjb2x1bW4gaW4gdGhlIGRhdGFmcmFtZQ0KQlJJQy5tb250aGx5ICU+JSBtdXRhdGVfYWxsKGlzLm5hKSAlPiUgc3VtbWFyaXplX2FsbChzdW0pDQoNCmBgYA0KDQpUbyBETzogY29tcHV0ZSBjb3JyZWxhdGlvbnMgYnkgc2VjdG9yICgxMCBzZWN0b3JzKQ0KDQpgYGB7cn0NCiMgcmVndWxhciBjb3JyZWxhdGlvbiBtYXRyaXggb2YgYWxsIChmb3VyKSBudW1lcmljIGF0dHJpYnV0ZXMNCmNvcihzZWxlY3QoQlJJQy5zdGF0aWMsIHdoZXJlKGlzLm51bWVyaWMpKSkNCmBgYA0KDQoNCioqU29tZSBjb252ZW50aW9uczoqKg0KDQpDaGFyYWN0ZXJpc3RpYyBzaG91bGQgYmUgY2FsY3VsYXRlZCBhcyBpbiBIYW5hdWVyICYgTGF1dGVyYmFjaCAoMjAxOSkgb3IgaW4gSGFuYXVlciAoMjAyMCkNCg0KQmlnIHN0b2NrcyBzaG91bGQgYmUgZGVmaW5lZCBhcyB0aGUgYmlnZ2VzdCBzdG9ja3Mgd2hpY2ggdG9nZXRoZXIgYWNjb3VudCBmb3IgOTAlIG9mIGENCmNvdW50cnkncyBhZ2dyZWdhdGVkIG1hcmtldCBjYXBpdGFsaXphdGlvbg0KQmVuY2htYXJrIHNob3VsZCBiZSBkZWZpbmVkIGFzIHRoZSBjYXAtd2VpZ2h0ZWQgdW5pdmVyc2Ugb2YgYmlnIHN0b2Nrcw0KUmV0dXJucyBzaG91bGQgYmUgaW4gVVNEDQpCcmVha3BvaW50cyAoZm9yIEZhbWEtRnJlbmNoIGZhY3RvcnMpIHNob3VsZCBiZSBjYWxjdWxhdGVkIG9uIGJpZyBzdG9ja3MgKGFzIGluIHRoZQ0KZXhjdXJzdXMpIGJ1dCBib3RoIHNtYWxsIGFuZCBiaWcgc3RvY2tzIGdvIGludG8gdGhlIGZhY3RvciBjYWxjdWxhdGlvbi4NCg0KIyBCZW5jaG1hcmsgQ2FsY3VsYXRpb24NCg0KYGBge3J9DQpsZW5ndGgoQlJJQy5zdGF0aWMkSWQpDQoNCmxlbmd0aChCUklDLnllYXJseSRJZCkNCg0KYGBgDQoNCmBgYHtyfQ0KIyBqb2luaW5nIHRoZSBtb250aGx5IGFuZCB0aGUgc3RhdGljIGRhdGFmcmFtZSBieSB0aGUgSWQgY29sdW1uIChyZXRhaW5pZyBhbGwgcm93cyBvZiBCUklDLnllYXJseSkNCmRmX2NvbWJpbmVkIDwtIGxlZnRfam9pbih4PUJSSUMubW9udGhseSx5PUJSSUMuc3RhdGljLGJ5PSJJZCIpDQoNCg0KaGVhZChkZl9jb21iaW5lZCkNCg0KDQoNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcnkoZGZfY29tYmluZWQkTVYuVVNEKQ0KYGBgDQoNCg0KYGBge3J9DQojIyBmaW5kaW5nIHRoZSBudW1iZXIgb2YgTkEgdmFsdWVzIGJ5IGNvbHVtbiBpbiB0aGUgZGF0YWZyYW1lDQpCUklDLnllYXJseSAlPiUgbXV0YXRlX2FsbChpcy5uYSkgJT4lIHN1bW1hcml6ZV9hbGwoc3VtKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCiMgbWFya3QgY2FwIChVU0QpOiBXQzA3MjEwDQoNCiMjIGZpbmRpbmcgdGhlIG51bWJlciBvZiBOQSB2YWx1ZXMgYnkgY29sdW1uIGluIHRoZSBkYXRhZnJhbWUNCmRmX2NvbWJpbmVkICU+JSBtdXRhdGVfYWxsKGlzLm5hKSAlPiUgc3VtbWFyaXplX2FsbChzdW0pDQpgYGANCg0KDQoNCg0KSWRlYTogY2FsY3VsYXRlIDkwJSBvZiB0aGUgc3VtIG9mIGFsbCBzdG9jayBtYXJrZXQgY2FwcyBwZXIgY291bnRyeSBhcyBhIHRpbWUgc2VyaWVzDQooc3RvcmUgdGhlIHJlc3VsdCBpbiBhIGNvbHVtbiApDQoNCmBgYHtyfQ0KIyBCaWcgc3RvY2tzIHNob3VsZCBiZSBkZWZpbmVkIGFzIHRoZSBiaWdnZXN0IHN0b2NrcyB3aGljaCB0b2dldGhlciBhY2NvdW50IGZvciA5MCUgb2YgIyBhIGNvdW50cnkncyBhZ2dyZWdhdGVkIG1hcmtldCBjYXBpdGFsaXphdGlvbg0KDQoNCiMgZ3JvdXBpbmcgdGhlIG1jYXAgdmFsdWVzIG9mIGluZGl2aWR1YWwgc3RvY2tzIGJ5IGNvdW50cnkNCm1jYXBfY291bnRyeSA8LSBkZl9jb21iaW5lZCAlPiUNCiAgZmlsdGVyKGRmX2NvbWJpbmVkJE1WLlVTRCAhPSAiTkEiKSAlPiUgDQogIGdyb3VwX2J5KGNvdW50cnkueCwgeW0pIA0KDQojIGNvbXB1dGluZyB0aGUgc3VtIG9mIHRoZSBpbmRpdmlkdWFsIHN0b2NrJ3MgbWFya2V0IGNhcHMgYnkgY291bnRyeQ0KY291bnRyeV9tY2FwIDwtIG1jYXBfY291bnRyeSAlPiUNCmdyb3VwX2J5KGNvdW50cnkueCwgeW0pICU+JQ0KICAgIHN1bW1hcml6ZShtY19zdW0gPSBzdW0oTVYuVVNEKSkNCg0KY291bnRyeV9tY2FwDQoNCg0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShjb3VudHJ5X21jYXAkbWNfc3VtW2NvdW50cnlfbWNhcCRjb3VudHJ5LnggPT0gIkJSQSJdKQ0Kc3VtbWFyeShjb3VudHJ5X21jYXAkbWNfc3VtW2NvdW50cnlfbWNhcCRjb3VudHJ5LnggPT0gIlJVUyJdKQ0Kc3VtbWFyeShjb3VudHJ5X21jYXAkbWNfc3VtW2NvdW50cnlfbWNhcCRjb3VudHJ5LnggPT0gIklORCJdKQ0Kc3VtbWFyeShjb3VudHJ5X21jYXAkbWNfc3VtW2NvdW50cnlfbWNhcCRjb3VudHJ5LnggPT0gIkNITiJdKQ0KYGBgDQoNCiMgRkY1Rk0gQ2FsdWxhdGlvbiBuZXcNCg0KYGBge3J9DQojIyAxIG1vbnRoIHQtYmlsbCByYXRlDQojIGxvYWQgZGF0YSBzaGVldCBmcm9tIEZyZW5jaCdzIHdlYnNpdGUNCmxpYnJhcnkocmVhZHIpDQpGRkRhdGEgPC0gcmVhZF9jc3YoIkZGX1Jlc2VhcmNoX0RhdGFfNV9GYWN0b3JzXzJ4My5DU1YiLCANCiAgICAgc2tpcCA9IDIpDQoNCiMgYWRkaW5nIGEgeW0gY29sdW1uIHRvIHJpc2sgZnJlZSByYXRlIGRhdGENCm9uZV9tX3RiaWxsIDwtIGFzLmRhdGEuZnJhbWUoRkZEYXRhW2MoIlgxIiwiUkYiKV1bMTo2OTMsXSkNCg0Kb25lX21fdGJpbGwkeW08LWFzLnllYXJtb24ob25lX21fdGJpbGwkWDEsICIlWSAlbSIpDQoNCiMgbWVyZ2Ugcmlzay1mcmVlIHJhdGUgKDEgbW9udGggdHJlYXN1cnkgYmlsbCByYXRlKSB3aXRoIG1vbnRobHkgZGF0YQ0KQlJJQy5tb250aGx5X2Z1bGwgPC0gbGVmdF9qb2luKHggPSBCUklDLm1vbnRobHksIHkgPSBvbmVfbV90YmlsbCwgYnkgPSAieW0iKQ0KDQojIG1ha2UgcmYgY29sdW1uIG51bWVyaWMNCkJSSUMubW9udGhseV9mdWxsJFJGIDwtIGFzLm51bWVyaWMoQlJJQy5tb250aGx5X2Z1bGwkUkYpDQoNCmBgYA0KDQojIGNhbGN1bGF0ZSBSTVJGDQoNCmBgYHtyfQ0KQlJJQy5tb250aGx5X2Z1bGwkUk1SRiA8LSBCUklDLm1vbnRobHlfZnVsbCRSRVQuVVNEIC0gQlJJQy5tb250aGx5X2Z1bGwkUkYNCmBgYA0KDQojIENhbGN1bGF0ZSBTTUIgYW5kIEhNTA0KY29tbWVudDogbmEgdmFsdWVzIGFwcGVhciBmb3Igc2l6ZSBjYWxjdWxhdGlvbiwgd2hpY2ggZGlmZmVycyBmcm9tIHdoYXQgaW4gdGhlIGV4Y3Vyc3VzDQpub3RlOiB3ZSBvbWl0dGVkIHRoZSBuYSdzIGZvciBmdXJ0aGVyIGNhbGN1bGF0aW9uIC0tPiBoYXMgdG8gYmUgY2xhcmlmaWVkIGluIHRoZSBRJkEgc2Vzc2lvbiB3aXRoIEhhbmF1ZXINCg0Kd2UgZGlkbid0IGNhbGN1bGF0ZSB0aGUgbGFnZ2VkIE1WIHlldCBsaW5lcyAyNzEsMzE1DQoNCmBgYHtyfQ0KIyMgRGV0ZXJtaW5lIHBvcnRmb2xpbyBicmVha3BvaW50cyBmb3IgU2l6ZQ0KIyBGYW1hLUZyZW5jaCB0YWtlIHRoZSBNViBmcm9tIGVuZC1vZi1KdW5lIGFuZCByZWJhbGFuY2UgeWVhcmx5DQpCUklDLm1vbnRobHlfZnVsbFssbW9udGggOj0gbW9udGgoRGF0ZSldDQpCUklDLm1vbnRobHlfZnVsbFsseWVhciA6PSB5ZWFyKERhdGUpXQ0KQlJJQy5tb250aGx5X2Z1bGxbLGhjanVuIDo9IGlmZWxzZShtb250aD49Nyx5ZWFyLHllYXItMSldDQoNCiMgZGV0ZXJtaW5lIHNpemUgcG9ydGZvbGlvIGFsbG9jYXRpb24gZnJvbSBKdWx5IG9uIHVzaW5nIGRhdGEgdGhhdCdzIHB1YmxpYyBmcm9tIGVuZC1vZi1KdW5lIG9uDQoNCiMgd2UgZGlkbid0IGNhbGN1bGF0ZSB0aGUgbGFnZ2VkIE1WIHlldCANCg0Kc2V0b3JkZXIoQlJJQy5tb250aGx5X2Z1bGwsRGF0ZSwtTVYuVVNEKQ0KaGxwdmFyaWFibGUgPC0gIEJSSUMubW9udGhseV9mdWxsW21vbnRoPT03ICYgIWlzLm5hKE1WLlVTRCksDQogICAgICAgICAgICAgICAgLihTaXplID0gaWZlbHNlKChjdW1zdW0oTVYuVVNEKS9zdW0oTVYuVVNEKSk+PTAuOSwiU21hbGwiLCJCaWciKSxJZCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnk9eWVhcl0NCg0KIyBNZXJnZSB0aGUgc2l6ZSBwb3J0Zm9saW8gYWxsb2NhdGlvbiBiYWNrIGZyb20gSnVseSBZIHRvIEp1bmUgWSsxDQpwYW5lbF9jb3VudHJ5IDwtIG1lcmdlKEJSSUMubW9udGhseV9mdWxsLGhscHZhcmlhYmxlLA0KICAgICAgICAgICAgICAgICAgICAgICBieS54PWMoImhjanVuIiwiSWQiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgYnkueT1jKCJ5ZWFyIiwiSWQiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxsLng9VCkNCg0KcGFuZWxfY291bnRyeV9ub05BIDwtIG5hLm9taXQocGFuZWxfY291bnRyeSxjb2xzID0gIlNpemUiKSANCg0KIyBtZXJnZSB5ZWFybHkgQk0gZGF0YSB3aXRoIG91ciB0YWJsZQ0KQlJJQy55ZWFybHlfaGVscGVyIDwtIHN1YnNldCggQlJJQy55ZWFybHksIHNlbGVjdCA9IGMoIklkIiwiY291bnRyeSIsIklDQlNVQyIsIllFQVIiLCJXQzAzNTAxIiwiV0MwNzIxMCIsIldDMDEwMDEiLCJXQzAxMDUxIiwiV0MwMTEwMSIsIldDMDEyNTEiLCJXQzAyOTk5IikgKQ0KQlJJQy55ZWFybHlfaGVscGVyJEJNIDwtIEJSSUMueWVhcmx5X2hlbHBlciRXQzAzNTAxIC8gQlJJQy55ZWFybHlfaGVscGVyJFdDMDcyMTANCg0KIyBkZWxldGUgTkEgcyBmcm9tIEJNIGNvbHVtbg0KQlJJQy55ZWFybHlfaGVscGVyIDwtIG5hLm9taXQoQlJJQy55ZWFybHlfaGVscGVyLGNvbHMgPSAiQk0iKQ0KDQpzdW1tYXJ5KEJSSUMueWVhcmx5X2hlbHBlciRCTSkNCg0KIyBlbGltaW5hdGluZyB1bnVzZWQgY29sdW1ucw0KcGFuZWxfY291bnRyeV9ub05BIDwtIHN1YnNldChwYW5lbF9jb3VudHJ5X25vTkEsIHNlbGVjdCA9IGMoImhjanVuIiwiSWQiLCJjb3VudHJ5IiwiTVYuVVNEIiwiUkVULlVTRCIsInltIiwiUkYiLCJtb250aCIsInllYXIiLCJTaXplIiwiRGF0ZSIpKQ0KDQpwYW5lbF9jb3VudHJ5X0JNIDwtIGlubmVyX2pvaW4oeCA9IHBhbmVsX2NvdW50cnlfbm9OQSx5ID0gQlJJQy55ZWFybHlfaGVscGVyLCBieSA9ICJJZCIpDQoNCg0KIyBEZXRlcm1pbmUgdGhlIEIvTSBicmVha3BvaW50cyBiYXNlZCBvbiBiaWcgc3RvY2tzIG9ubHkNCmhscHZhcmlhYmxlMiA8LSBwYW5lbF9jb3VudHJ5X0JNW21vbnRoPT03ICYgIWlzLm5hKEJNKSAmIFNpemU9PSJCaWciLCAuKGJtX2JiMzAgPSBxdWFudGlsZShCTSAsIHByb2JzID0gYygwLjMpLCBuYS5ybT1UKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJtX2JiNzAgPSBxdWFudGlsZShCTSAsIHByb2JzID0gYygwLjcpLCBuYS5ybT1UKSksYnk9eWVhcl0NCiAgICAgICAgICAgICAgDQojIE1lcmdlIHRoZSBCL00gcG9ydGZvbGlvIGFsbG9jYXRpb24gYmFjayBmcm9tIEp1bHkgWSB0byBKdW5lIFkrMQ0KcGFuZWxfY291bnRyeV9uZXcgPC0gbWVyZ2UocGFuZWxfY291bnRyeV9CTSxobHB2YXJpYWJsZTIsDQogICAgICAgICAgICAgICAgICAgICAgIGJ5Lng9YygiaGNqdW4iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgYnkueT1jKCJ5ZWFyIiksDQogICAgICAgICAgICAgICAgICAgICAgIGFsbC54PVQpDQoNCnBhbmVsX2NvdW50cnlfbmV3WyAsIHBmLmJtIDo9IGlmZWxzZShCTT5ibV9iYjcwLCJIaWdoIixpZmVsc2UoKEJNPD1ibV9iYjcwICYgQk0+Ym1fYmIzMCksIk5ldXRyYWwiLGlmZWxzZShCTTw9Ym1fYmIzMCwiTG93IixOQSkpKV0NCg0KcGFuZWxfY291bnRyeV9uZXdbLCBTSVpFX1ZBTFVFIDo9IHBhc3RlMChTaXplLCIuIixwZi5ibSldDQoNCiMgd2UgdXNlZCBNVi5VU0QgaW5zdGVhZCBvZiB0aGUgbGFnZ2VkIE1WDQoNCnBvcnRmb2xpb19yZXR1cm5zIDwtIHBhbmVsX2NvdW50cnlfbmV3WyFpcy5uYShTaXplKSAmICFpcy5uYShwZi5ibSldICU+JSAjIHRoaXMgb3BlcmF0b3IgbmVzdHMgZnVuY3Rpb25zDQogIGdyb3VwX2J5KERhdGUsU0laRV9WQUxVRSkgJT4lICMgZG8gImV2ZXJ5dGhpbmciIGZvciB0aGUgZ3JvdXBzIHNwZWNpZmllZCBoZXJlDQogIHN1bW1hcml6ZShyZXQucG9ydCA9IHdlaWdodGVkLm1lYW4oUkVULlVTRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNVi5VU0QpKSAlPiUgIyB2dyByZXR1cm5zIHVzaW5nIGxhZ2dlZCBtY2FwDQogIHNwcmVhZChTSVpFX1ZBTFVFLHJldC5wb3J0KSAlPiUgIyBjcmVhdGUgb25lIGNvbHVtbiBmb3IgZWFjaCBncm91cA0KICBtdXRhdGUoDQogICAgU21hbGwgPSAoU21hbGwuSGlnaCArIFNtYWxsLk5ldXRyYWwgKyBTbWFsbC5Mb3cpLzMsICMganVzdCBleGVtcGxhcnkNCiAgICBCaWcgPSAoQmlnLkhpZ2ggKyBCaWcuTmV1dHJhbCArIEJpZy5Mb3cpLzMsDQogICAgU01CID0gU21hbGwtQmlnLA0KICAgIEhpZ2ggPSAoU21hbGwuSGlnaCArIEJpZy5IaWdoKS8yLA0KICAgIExvdyA9IChTbWFsbC5Mb3cgKyBCaWcuTG93KS8yLA0KICAgIEhNTCA9IEhpZ2gtTG93DQogICkNCg0KcG9ydGZvbGlvX3JldHVybnMgPC0gYXMuZGF0YS50YWJsZShwb3J0Zm9saW9fcmV0dXJucykNCg0KaGVhZChwb3J0Zm9saW9fcmV0dXJucykNCiANCmBgYA0KIA0KIyBSTVcNCnByb2ZpdGFiaWxpdHk6IE9QL0JFOiBPcGVyYXRpbmcgcHJvZml0cy10by1ib29rIGVxdWl0eS4gV2UgbWVhc3VyZSBvcGVyYXRpbmcgcHJvZml0cy10by1ib29rIGVxdWl0eSBhcyBpbiBGYW1hIGFuZCBGcmVuY2ggKDIwMTUpIGFzIHNhbGVzIG9yIHJldmVudWVzIChXQzAxMDAxKSBtaW51cyBjb3N0IG9mIGdvb2RzIHNvbGQgKFdDMDEwNTEpLCBtaW51cyBzZWxsaW5nLCBnZW5lcmFsLCBhbmQgYWRtaW5pc3RyYXRpdmUgZXhwZW5zZXMgKFdDMDExMDEpLCBtaW51cyBpbnRlcmVzdCBleHBlbnNlIChXQzAxMjUxKTsgYWxsIGRpdmlkZWQgYnkgYm9vayBlcXVpdHkuIChIYW5hdWVyLCAyMDE5LCBwLiAyODQpDQpgYGB7cn0NCiMgdXNlIEJSSUMueWVhcmx5X2hlbHBlcg0KDQoNCg0KYGBgDQoNCg0KDQoNCg0KIyBDTUENCmludmVzdG1lbnQ6IEFzIGluIENvb3BlciBldCBhbC4gKDIwMDgpLCB3ZSBtZWFzdXJlIGFzc2V0IGdyb3d0aCBpbiBKdW5lIG9mIHllYXIgeSBhcyB0aGUgcGVyY2VudGFnZSBjaGFuZ2UgaW4gdG90YWwgYXNzZXRzIChXQzAyOTk5KSBmcm9tIGZpc2NhbCB5ZWFyIGVuZGluZyBpbiBjYWxlbmRhciB5ZWFyIHniiJIyIHRvIGZpc2NhbCB5ZWFyIGVuZGluZyBpbiBjYWxlbmRhciB5ZWFyIHniiJIxLg0KYGBge3J9DQojIHVzZSBCUklDLnllYXJseV9oZWxwZXINCg0KDQoNCmBgYA0KDQojIFN0cmF0ZWd5DQoNCg0KYGBge3J9DQojaW5zdGFsbC5wYWNrYWdlcygicGxtIikNCmxpYnJhcnkocGxtKQ0KbGlicmFyeShkcGx5cikNCg0Kc3RyYXRlZ3lfZGYgPC0gcGRhdGEuZnJhbWUoQlJJQy5tb250aGx5LGluZGV4ID0gYygiSWQiLCJ5bSIpKQ0KDQojIGNhbGN1bGF0ZSBzZCBvZiByZXR1cm4gYnkgeW0NCnNkX2hlbHAgPC0gc3Vic2V0KEJSSUMubW9udGhseSxzZWxlY3QgPSBjKCJJZCIsInltIiwiUkVULlVTRCIpKQ0Kc2RfaGVscCA8LSBuYS5vbWl0KHNkX2hlbHAsY29scyA9IFJFVC5VU0QpICMgbWF5IGJlIGRlbGV0ZWQsIGlmIHJlZHVuZGFudA0KDQojIG1vbnRobHkgYmFzaXMNCm51bWJlcl9vZl9zdG9ja3MgPC0gYWdncmVnYXRlKC5+IHltLCBkYXRhID0gc2RfaGVscCxGVU4gPSBOUk9XKSAjIGFsdGVybmF0aXZlOiBzZF9oZWxwICU+JSBjb3VudCh5bSkNCm1lYW5fcmV0dXJuIDwtIGFnZ3JlZ2F0ZSgufiB5bSwgZGF0YSA9IHNkX2hlbHAsRlVOID0gbWVhbikNCg0KcGxvdChzZF9yZXQkeW0sc2RfcmV0JFJFVC5VU0QpDQpwbG90KG1lYW5fcmV0JHltLG1lYW5fcmV0JFJFVC5VU0QpDQoNCiMgeWVhcmx5IGJhc2lzDQoNCmBgYA0KDQoNCg0KYGBge3J9DQojIHNvcnRpbmcgdGhlIHN0b2NrcyBieSBtYXJrZXQgY2FwIGFuZCBleHRyYWN0aW5nIHRoZSBJU0lOcyBvZiB0aGUgYmlnZ2VzdCBvbmVzIHRoYXQgbWFrZSB1cCA5MCUgb2YgYSBjb3VudHJ5J3MgbWFya2V0IGNhcA0KDQojIFJVU1NJQQ0KIyA5MCUgb2YgdGhlIG1hcmtldCBjYXAgaW4gUnVzc2lhOiANCjAuOSpjb3VudHJ5X21jYXAkbWNfc3VtWzRdDQoNCiMgc3Vic2V0dGluZyBhbGwgUnVzc2lhbiBzdG9ja3MNCnJ1c3NpYW5fc3RvY2tzIDwtIGFzLmRhdGEuZnJhbWUobWNhcF9jb3VudHJ5KSAlPiUNCiAgIGZpbHRlcihjb3VudHJ5LnggPT0gIlJVUyIpIA0KDQojIHNvcnRpbmcgdGhlIGRhdGFmcmFtZSBvZiBydXNzaWFuIHN0b2NrcyBieSBkZWNyZWFzaW5nIG1hcmtldCBjYXANCnJ1c3NpYW5fc3RvY2tzIDwtIHJ1c3NpYW5fc3RvY2tzW29yZGVyKHJ1c3NpYW5fc3RvY2tzJFdDMDcyMTAsZGVjcmVhc2luZyA9IFRSVUUpLF0NCiANCiMgZmlsdGVyaW5nIG91dCB0aGUgYmlnIHN0b2NrcyB3aGljaCBzdW0gdXAgdG8gOTAlIG9mIHRoZSBtYXJrZXQgY2FwIG9mIFJ1c3NpYW4gc3RvY2tzDQpiaWdfc3RvY2tzX1JVUyA8LSBydXNzaWFuX3N0b2Nrc1tjdW1zdW0ocnVzc2lhbl9zdG9ja3MkV0MwNzIxMCkgPD0gMC45KmNvdW50cnlfbWNhcCRtY19zdW1bNF0sXQ0KDQpiaWdfc3RvY2tzX1JVUw0KDQoNCg0KYGBgDQoNCg0KaWRlYToNCg0KYmlnX3N0b2NrcyA8LSBtY2FwX2NvdW50cnkgJT4lDQogIHNlbGVjdChJU0lOKSAlPiUNCiBzb3J0KG1jYXBfY291bnRyeSRXQzA3MjEwLCBkZWNyZWFzaW5nPVQpICAlPiUNCiAgZmlsdGVyKG1jYXBfY291bnRyeSRXQzA3MjEwIDw9IDAuOSpjb3VudHJ5X21jYXAkbWNfc3VtKQ0KDQpiaWdfc3RvY2tzDQoNCmBgYHtyfQ0KIyBzb3J0aW5nIHRoZSBzdG9ja3MgYnkgbWFya2V0IGNhcCBhbmQgZXh0cmFjdGluZyB0aGUgSVNJTnMgb2YgdGhlIGJpZ2dlc3Qgb25lcyB0aGF0IG1ha2UgdXAgOTAlIG9mIGEgY291bnRyeSdzIG1hcmtldCBjYXANCg0KIyBSVVNTSUENCiMgOTAlIG9mIHRoZSBtYXJrZXQgY2FwIGluIFJ1c3NpYTogDQowLjkqY291bnRyeV9tY2FwJG1jX3N1bVs0XQ0KDQojIHN1YnNldHRpbmcgYWxsIFJ1c3NpYW4gc3RvY2tzDQpydXNzaWFuX3N0b2NrcyA8LSBhcy5kYXRhLmZyYW1lKG1jYXBfY291bnRyeSkgJT4lDQogICBmaWx0ZXIoY291bnRyeS54ID09ICJSVVMiKSANCg0KIyBzb3J0aW5nIHRoZSBkYXRhZnJhbWUgb2YgcnVzc2lhbiBzdG9ja3MgYnkgZGVjcmVhc2luZyBtYXJrZXQgY2FwDQpydXNzaWFuX3N0b2NrcyA8LSBydXNzaWFuX3N0b2Nrc1tvcmRlcihydXNzaWFuX3N0b2NrcyRXQzA3MjEwLGRlY3JlYXNpbmcgPSBUUlVFKSxdDQogDQojIGZpbHRlcmluZyBvdXQgdGhlIGJpZyBzdG9ja3Mgd2hpY2ggc3VtIHVwIHRvIDkwJSBvZiB0aGUgbWFya2V0IGNhcCBvZiBSdXNzaWFuIHN0b2Nrcw0KYmlnX3N0b2Nrc19SVVMgPC0gcnVzc2lhbl9zdG9ja3NbY3Vtc3VtKHJ1c3NpYW5fc3RvY2tzJFdDMDcyMTApIDw9IDAuOSpjb3VudHJ5X21jYXAkbWNfc3VtWzRdLF0NCg0KYmlnX3N0b2Nrc19SVVMNCg0KDQoNCiAgDQpgYGANCg0KDQojIENhbGN1bGF0aW5nIHRoZSBzaXplIHBvcnRmb2xpb3MNCg0KDQoNCg0K